package com.yorge.service;

import cn.hutool.core.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Service
@Slf4j
public class BingFaTest {

    // 单例测试
    // 多次调用。看看有没有可能请求出的时候，另一个线程请求入，导致请求出为空
//    private String aaa = null;
    // 实现变量生效
    private volatile String aaa2 = null;
//    private ThreadLocal<String> aaa = new ThreadLocal<>();

    private ThreadLocal<String> aaa = new ThreadLocal<>();

    public void singleTest() throws Exception {
        String ss = RandomUtil.randomString(4);
        log.info("{} 请求入：{}", ss, aaa.get());
        aaa.set(RandomUtil.randomString(5));
        log.info("{} 请求中：{}", ss, aaa.get());
        TimeUnit.SECONDS.sleep(3);
        log.info("{} 请求出：{}", ss, aaa.get());
    }

    public void setSingle() throws Exception {
        log.info("setSingle1: {}", aaa);
        TimeUnit.SECONDS.sleep(6);
        log.info("setSingle2: {}", aaa);
    }

    public void RunnableTest(Runnable r) {
        r.run();
        Semaphore semaphore;
    }

    public void testSemaphore() throws InterruptedException {
        log.info("入");
        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 5; i++) {
            int finalI = i;
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(finalI);
                        semaphore.acquire();
                        log.info("semaphore: {}", RandomUtil.randomString(5));
                        // 获取等待的线程数
                        log.info(String.valueOf(semaphore.getQueueLength()));
                        TimeUnit.SECONDS.sleep(2);
                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };

            r.run();
        }
        log.info("出");
    }

    public void testCondition() throws InterruptedException {
        Lock lock = new ReentrantLock();
        Condition c = lock.newCondition();
        log.info("开始等待");
        c.await();

        log.info("结束等待");
        c.signal();
        lock.unlock();
    }


    public void testBlokingQueue() throws InterruptedException {
        log.info("入");
        BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>();

        for (int i = 0; i < 5; i++) {
            int finalI = i;
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(finalI);
//                        semaphore.acquire();
                        log.info("semaphore: {}", RandomUtil.randomString(5));
                        // 获取等待的线程数
//                        log.info(String.valueOf(semaphore.getQueueLength()));
                        TimeUnit.SECONDS.sleep(2);
//                        semaphore.release();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };

            r.run();
        }
        log.info("出");
    }

    // 设置值后，读取值的过程中，另外一个线程正在修改。是读取之前的值还是之后的值。
    private final ConcurrentHashMap<Integer, Long> map = new ConcurrentHashMap<>();
//    Hashtable<Integer, Long> hashtable = new Hashtable<Integer, Long>();

    public void testMap() throws InterruptedException {
        Long oldValue = map.get(1);
        if (map.get(1) != null) {
//            map.computeIfAbsent(1, k -> setMapValue(oldValue));
            map.put(1, setMapValue(oldValue));
        } else {
            map.put(1, 1l);
        }
//        hashtable.put(1, setMapValue(oldValue));
        log.info(map.get(1) + "");
    }
    public Long setMapValue(Long oldValue) throws InterruptedException {
        log.info("oldValue: {}", oldValue);
        TimeUnit.SECONDS.sleep(3);
        Long newValue = oldValue + 1;
        log.info("newValue: {}", newValue);
        return newValue;
    }

}

